<template>
  <div class="game-container">
    <div class="game-header">
      <div class="score">分数: {{ score }}</div>
      <div class="timer">时间: {{ formatTime(timeLeft) }}</div>
    </div>
    <div ref="gameCanvas" class="game-canvas"></div>
    <div v-if="gameOver" class="game-over">
      <h2>游戏结束!</h2>
      <p>你的最终得分: {{ score }}</p>
      <button @click="resetGame">重新开始</button>
    </div>
    <div v-if="showNoMatch" class="no-match">没有可连接的瓦片，重新排列中...</div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import * as PIXI from 'pixi.js'
import { gsap } from 'gsap'
const CANVAS_PADDING = 40 // 增加40像素的边距

console.log(PIXI)

// 游戏配置
const BOARD_SIZE = 16
const TILE_SIZE = 40
const TILE_GAP = 2
const COLORS = [
  0xff0000, // 红
  0xff7f00, // 橙红
  0xffff00, // 黄
  0x7fff00, // 青柠
  0x00ff00, // 绿
  0x00ffff, // 青
  0x007fff, // 深蓝
  0x0000ff, // 蓝
  0x7f00ff, // 紫罗兰
  0xff00ff, // 品红
  0xff007f, // 粉红
  0x808080, // 灰
  0xa0522d, // 棕
  0xffa500, // 橙
  0xffd700, // 金
  0x008000, // 深绿
]
const MAX_TURNS = 2

// 游戏状态
const gameCanvas = ref<HTMLDivElement | null>(null)
const app = ref<PIXI.Application | null>(null)
const board = ref<number[][]>([])
const selectedTile = ref<{ x: number; y: number } | null>(null)
const score = ref(0)
const timeLeft = ref(600)
const gameOver = ref(false)
const showNoMatch = ref(false)
const timer = ref<NodeJS.Timeout | null>(null)
const connectionLine = ref<PIXI.Graphics | null>(null)

// 初始化游戏
const initGame = async () => {
  if (!gameCanvas.value) return

  // 创建 PixiJS 应用
  app.value = new PIXI.Application()

  await app.value.init({
    width: BOARD_SIZE * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING * 2,
    height: BOARD_SIZE * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING * 2,
    backgroundColor: 0x0a192f,
    antialias: true,
  })
  gameCanvas.value.appendChild(app.value.canvas as HTMLCanvasElement)

  initBoard()
  drawBoard()
  startTimer()
}

// 优化棋盘初始化，减少同色相邻
// 优化后的棋盘初始化函数 - 保证配对且随机
const initBoard = () => {
  const totalTiles = BOARD_SIZE * BOARD_SIZE
  const colors = [...COLORS] // 创建颜色副本避免修改原数组

  // 1. 精确控制颜色分布（每个颜色出现16次）
  const colorPairs: number[] = []
  for (const color of colors) {
    // 每个颜色生成8对（16个格子）
    for (let i = 0; i < 8; i++) {
      colorPairs.push(color, color)
    }
  }
  console.log(colorPairs)
  console.log(totalTiles)
  if (colorPairs.length !== totalTiles) {
    throw new Error('Color pairs count mismatch!')
  }
  shuffleArray(colorPairs) // 完全随机洗牌

  // 2. 初始化棋盘和位置系统
  board.value = Array.from({ length: BOARD_SIZE }, () => Array(BOARD_SIZE).fill(0))

  const positions = Array.from({ length: totalTiles }, (_, i) => ({
    x: i % BOARD_SIZE,
    y: Math.floor(i / BOARD_SIZE),
  }))
  console.log('positions-->', positions.toString())
  // 3. 智能放置算法（严格避免相邻）
  for (let i = 0; i < colorPairs.length; i++) {
    const targetColor = colorPairs[i]
    let placed = false

    // 每次尝试都随机打乱剩余位置
    shuffleArray(positions)

    // 优先寻找绝对安全位置
    for (const pos of positions) {
      if (board.value[pos.y][pos.x] !== 0) continue

      // 检查四个方向
      const hasConflict = [
        { x: 0, y: -1 },
        { x: 1, y: 0 },
        { x: 0, y: 1 },
        { x: -1, y: 0 },
      ].some((dir) => {
        const nx = pos.x + dir.x
        const ny = pos.y + dir.y
        return (
          nx >= 0 &&
          nx < BOARD_SIZE &&
          ny >= 0 &&
          ny < BOARD_SIZE &&
          board.value[ny][nx] === targetColor
        )
      })

      if (!hasConflict) {
        board.value[pos.y][pos.x] = targetColor
        positions.splice(positions.indexOf(pos), 1)
        placed = true
        break
      }
    }

    // 回退方案：随机放置（理论上极少触发）
    if (!placed) {
      const randomPos = positions.find((p) => board.value[p.y][p.x] === 0 && positions.includes(p))!
      board.value[randomPos.y][randomPos.x] = targetColor
      positions.splice(positions.indexOf(randomPos), 1)
    }
  }
}

// 优化后的洗牌算法（Fisher-Yates）
const shuffleArray = <T,>(array: T[]): T[] => {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[array[i], array[j]] = [array[j], array[i]]
  }
  return array
}

// 绘制棋盘
const drawBoard = () => {
  if (!app.value) return

  app.value.stage.removeChildren()

  if (connectionLine.value) {
    app.value.stage.addChild(connectionLine.value)
  }

  for (let y = 0; y < BOARD_SIZE; y++) {
    for (let x = 0; x < BOARD_SIZE; x++) {
      const color = board.value[y][x]
      if (color === 0) continue

      const tile = new PIXI.Graphics()
      tile.roundRect(0, 0, TILE_SIZE, TILE_SIZE, TILE_SIZE * 0.1)
      tile.fill(color)
      // 调整瓦片位置（加上边距）
      tile.x = x * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING
      tile.y = y * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING
      tile.interactive = true
      tile.label = `${x},${y}`
      tile.on('pointerdown', () => handleTileClick(x, y))
      app.value.stage.addChild(tile)
    }
  }
}

// 处理瓦片点击
const handleTileClick = (x: number, y: number) => {
  if (gameOver.value || showNoMatch.value) return
  if (board.value[y][x] === 0) return

  // 检查瓦片是否存在
  if (!board.value[y]?.[x] || board.value[y][x] === 0) {
    // 如果点击了无效位置，取消当前选择
    if (selectedTile.value) {
      highlightTile(selectedTile.value.x, selectedTile.value.y, false)
      selectedTile.value = null
    }
    return
  }

  // 如果没有选中的瓦片，选择当前瓦片
  if (!selectedTile.value) {
    selectedTile.value = { x, y }
    highlightTile(x, y, true)
    return
  }

  // 如果点击了已选中的瓦片，取消选择
  if (selectedTile.value.x === x && selectedTile.value.y === y) {
    highlightTile(x, y, false)
    selectedTile.value = null
    return
  }

  // 检查颜色是否匹配
  const firstTile = selectedTile.value
  const secondTile = { x, y }

  if (board.value[firstTile.y][firstTile.x] !== board.value[secondTile.y][secondTile.x]) {
    // 颜色不匹配，取消选择
    highlightTile(firstTile.x, firstTile.y, false)
    selectedTile.value = null
    return
  }
  // 查找路径
  const { path } = findPath(firstTile, secondTile)
  if (path) {
    drawConnectionLine(path)
    removeTiles(firstTile, secondTile)
    score.value += 10
    selectedTile.value = null
  } else {
    highlightTile(firstTile.x, firstTile.y, false)
    selectedTile.value = null
  }
}

// 高亮瓦片
const highlightTile = (x: number, y: number, highlight: boolean) => {
  if (!app.value) return

  const tile = app.value.stage.getChildByName(`${x},${y}`) as PIXI.Graphics
  if (!tile) return

  gsap.to(tile, {
    alpha: highlight ? 0.7 : 1,
    scale: highlight ? 1.1 : 1,
    duration: 0.2,
  })
}

// BFS查找路径（支持最外层连接）
const findPath = (
  start: { x: number; y: number },
  end: { x: number; y: number },
  timeout = 100,
): { path: { x: number; y: number }[] | null; timeout: boolean } => {
  const startTime = Date.now()
  if (start.x === end.x && start.y === end.y) return { path: null, timeout: false }
  // 添加最大步数限制防止无限循环
  const MAX_STEPS = BOARD_SIZE * BOARD_SIZE * 2
  const stepCount = 0

  const directions = [
    { x: 0, y: -1 },
    { x: 1, y: 0 },
    { x: 0, y: 1 },
    { x: -1, y: 0 },
  ]

  const queue: {
    x: number
    y: number
    path: { x: number; y: number }[]
    turns: number
    lastDir?: { x: number; y: number }
  }[] = [{ x: start.x, y: start.y, path: [{ x: start.x, y: start.y }], turns: 0 }]
  const visited = new Set<string>()
  visited.add(`${start.x},${start.y}`)

  while (queue.length > 0 && stepCount < MAX_STEPS && Date.now() - startTime < timeout) {
    const current = queue.shift()!

    if (current.x === end.x && current.y === end.y) {
      return { path: current.path, timeout: false }
    }

    if (current.turns > MAX_TURNS) continue

    for (const dir of directions) {
      const newX = current.x + dir.x
      const newY = current.y + dir.y

      // 允许超出边界的虚拟位置（最外层连接）
      let isVirtual = false
      if (newX < 0 || newX >= BOARD_SIZE || newY < 0 || newY >= BOARD_SIZE) {
        isVirtual = true
      }

      // 如果不是虚拟位置且不是终点/起点，检查是否有瓦片
      if (
        !isVirtual &&
        !(newX === end.x && newY === end.y) &&
        !(newX === start.x && newY === start.y) &&
        board.value[newY][newX] !== 0
      ) {
        continue
      }

      const newPosKey = `${newX},${newY}`
      if (visited.has(newPosKey)) continue

      let turns = current.turns
      if (current.path.length > 1) {
        const prev = current.path[current.path.length - 2]
        const lastDir = {
          x: current.x - prev.x,
          y: current.y - prev.y,
        }
        if (lastDir.x !== dir.x || lastDir.y !== dir.y) {
          turns++
        }
      }

      if (turns > MAX_TURNS) continue

      visited.add(newPosKey)
      queue.push({
        x: newX,
        y: newY,
        path: [...current.path, { x: newX, y: newY }],
        turns,
        lastDir: dir,
      })
    }
  }

  return { path: null, timeout: queue.length > 0 }
}

// 绘制连接线（重点优化）
// 修改绘制连接线函数
const drawConnectionLine = (path: { x: number; y: number }[]) => {
  if (!app.value) return

  if (connectionLine.value) {
    app.value.stage.removeChild(connectionLine.value)
  }

  connectionLine.value = new PIXI.Graphics()
  connectionLine.value.setStrokeStyle({ width: 2, color: 0xff0000 })

  // 计算路径点坐标（考虑画布边距）
  const points = path.map((pos) => {
    // 将棋盘坐标转换为像素坐标
    let x = pos.x
    let y = pos.y

    // 处理超出边界的情况
    x = Math.max(-1, Math.min(x, BOARD_SIZE))
    y = Math.max(-1, Math.min(y, BOARD_SIZE))

    // 计算实际像素位置（考虑边距）
    const px = (x + 0.5) * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING
    const py = (y + 0.5) * (TILE_SIZE + TILE_GAP) + TILE_GAP + CANVAS_PADDING

    return new PIXI.Point(px, py)
  })

  // 绘制连接线
  connectionLine.value.moveTo(points[0].x, points[0].y)
  for (let i = 1; i < points.length; i++) {
    connectionLine.value.lineTo(points[i].x, points[i].y)
  }
  connectionLine.value.stroke()
  // // 添加发光效果
  // const glow = new PIXI.filters.GlowFilter({
  //   distance: 15,
  //   outerStrength: 3,
  //   innerStrength: 1,
  //   color: 0xffffff,
  //   quality: 0.8,
  // })
  // connectionLine.value.filters = [glow]

  app.value.stage.addChild(connectionLine.value)

  // 动画效果
  connectionLine.value.alpha = 0
  gsap.to(connectionLine.value, {
    alpha: 1,
    duration: 0.3,
  })
}

// 移除瓦片
const removeTiles = (first: { x: number; y: number }, second: { x: number; y: number }) => {
  if (!app.value) return

  const firstTile = app.value.stage.getChildByName(`${first.x},${first.y}`) as PIXI.Graphics
  const secondTile = app.value.stage.getChildByName(`${second.x},${second.y}`) as PIXI.Graphics

  gsap.to([firstTile, secondTile], {
    alpha: 0,
    scale: 0,
    duration: 0.3,
    onComplete: () => {
      board.value[first.y][first.x] = 0
      board.value[second.y][second.x] = 0
      app.value?.stage.removeChild(firstTile)
      app.value?.stage.removeChild(secondTile)
      checkGameStatus()

      // 延迟后移除连接线
      gsap.delayedCall(1, () => {
        if (connectionLine.value && app.value?.stage.children.includes(connectionLine.value)) {
          app.value.stage.removeChild(connectionLine.value)
          connectionLine.value = null
        }
      })
    },
  })
}

// 检查游戏状态
const checkGameStatus = () => {
  if (!hasValidMoves()) {
    showNoMatch.value = true
    gsap.delayedCall(1.5, () => {
      refreshBoard()
      showNoMatch.value = false
    })
  }

  let allCleared = true
  for (let y = 0; y < BOARD_SIZE; y++) {
    for (let x = 0; x < BOARD_SIZE; x++) {
      if (board.value[y][x] !== 0) {
        allCleared = false
        break
      }
    }
    if (!allCleared) break
  }

  if (allCleared) {
    gameOver.value = true
    if (timer.value) clearInterval(timer.value)
  }
}

// 优化后的有效移动检查
const hasValidMoves = (): boolean => {
  const tiles: { x: number; y: number; color: number }[] = []

  // 1. 先收集所有非空瓦片
  for (let y = 0; y < BOARD_SIZE; y++) {
    for (let x = 0; x < BOARD_SIZE; x++) {
      if (board.value[y][x] !== 0) {
        tiles.push({ x, y, color: board.value[y][x] })
      }
    }
  }

  // 2. 优化检查顺序：先检查附近瓦片
  for (let i = 0; i < tiles.length; i++) {
    for (let j = i + 1; j < Math.min(i + 20, tiles.length); j++) {
      // 限制检查范围
      if (tiles[i].color === tiles[j].color) {
        const { path, timeout } = findPath(tiles[i], tiles[j])
        if (path) return true
        if (timeout) break // 超时则跳过
      }
    }
  }
  return false
}

// 刷新棋盘
const refreshBoard = () => {
  const remainingTiles: { x: number; y: number; color: number }[] = []
  for (let y = 0; y < BOARD_SIZE; y++) {
    for (let x = 0; x < BOARD_SIZE; x++) {
      if (board.value[y][x] !== 0) {
        remainingTiles.push({ x, y, color: board.value[y][x] })
      }
    }
  }

  // 优化排列
  const colors = remainingTiles.map((tile) => tile.color)
  let shuffledColors = shuffleArray(colors)

  let optimized = false
  let attempts = 0
  const maxAttempts = 5

  while (!optimized && attempts < maxAttempts) {
    attempts++
    let hasAdjacentSameColor = false

    for (let i = 0; i < remainingTiles.length; i++) {
      const tile = remainingTiles[i]
      const directions = [
        { x: 0, y: -1 },
        { x: 1, y: 0 },
        { x: 0, y: 1 },
        { x: -1, y: 0 },
      ]

      for (const dir of directions) {
        const nx = tile.x + dir.x
        const ny = tile.y + dir.y
        if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE) {
          const neighborIndex = remainingTiles.findIndex((t) => t.x === nx && t.y === ny)
          if (neighborIndex !== -1 && shuffledColors[i] === shuffledColors[neighborIndex]) {
            hasAdjacentSameColor = true
            break
          }
        }
      }
      if (hasAdjacentSameColor) break
    }

    if (!hasAdjacentSameColor) {
      optimized = true
    } else {
      shuffledColors = shuffleArray(shuffledColors)
    }
  }

  // 应用新颜色
  for (let i = 0; i < remainingTiles.length; i++) {
    const tile = remainingTiles[i]
    board.value[tile.y][tile.x] = shuffledColors[i]
  }

  drawBoard()
}

// 计时器
const startTimer = () => {
  if (timer.value) clearInterval(timer.value)
  timeLeft.value = 600
  timer.value = setInterval(() => {
    timeLeft.value--
    if (timeLeft.value <= 0) {
      gameOver.value = true
      if (timer.value) clearInterval(timer.value)
    }
  }, 1000)
}

const formatTime = (seconds: number) => {
  const mins = Math.floor(seconds / 60)
  const secs = seconds % 60
  return `${mins}:${secs < 10 ? '0' : ''}${secs}`
}

const resetGame = () => {
  if (timer.value) clearInterval(timer.value)
  score.value = 0
  gameOver.value = false
  selectedTile.value = null
  showNoMatch.value = false
  if (connectionLine.value) {
    app.value?.stage.removeChild(connectionLine.value)
    connectionLine.value = null
  }
  initBoard()
  drawBoard()
  startTimer()
}

onMounted(() => {
  initGame()
})

onUnmounted(() => {
  if (timer.value) clearInterval(timer.value)
  if (app.value) {
    app.value.destroy(true)
    app.value = null
  }
})
</script>

<style scoped>
.game-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: Arial, sans-serif;
  margin-top: 20px;
  position: relative;
}

.game-header {
  display: flex;
  justify-content: space-between;
  width: 100%;
  max-width: 630px;
  margin-bottom: 10px;
  font-size: 18px;
  font-weight: bold;
  color: #333;
}

.game-canvas {
  margin: 0 auto;
  border: 2px solid #666;
  border-radius: 5px;
}

.game-over {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 20px;
  border-radius: 10px;
  text-align: center;
  z-index: 100;
}

.game-over button {
  margin-top: 15px;
  padding: 8px 16px;
  background: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
}

.game-over button:hover {
  background: #45a049;
}

.no-match {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 15px 25px;
  border-radius: 5px;
  text-align: center;
  z-index: 100;
  animation: fadeInOut 1.5s ease-in-out;
}

@keyframes fadeInOut {
  0% {
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
</style>
